[AWS IoT Greenglass V2] 100円ショップの Bluetooth リモコン シャッターでパトランプ回してみました
1 はじめに
IoT事業部の平内(SIN)です。
唐突ですが、パトランプ回してみました。ON/OFFに使用したのは、100円ショップ(330円)で販売されているBluetooth リモコン シャッターです。
下の動画は、動作 を確認している様子です。
2つあるボタンで、それぞれON/OFFするようになっています。なお、Bluetoothで取得したボタン押下の情報は、MQTTにPublishされ、Sabscribeしているデバイスが、そのPayloadに基づいてパトランプを操作しています。
操作指示がMQTTのメッセージなので、IoT Coreのテスト画面からメッセージを送っても、動作できていることが分かります。これで、地球の裏側のパトランプも操作できるはずです。
2 構成
構成は、以下の通りです。
デバイス側で動作するプログラムは、Greengrass V2のコンポーネントとして作成されています。 図中の左右のGreengrassで動作するコンポーネントは、同一のものです。 末端デバイスとしてリモコンを繋ぐか、パトライトを繋ぐかで役割が変わるイメージです。
また、MQTTメッセージがトリガですので、1つのリモコンで、複数のパトライトを操作することも可能です。
3 Bluetooth リモコン シャッター
使用したリモコンです。現在は、ダイソーで品切れになっているようですが、Amazonnでも購入できます。まったく同じものでは無いですが、Can★Doでは、最近でも店頭に並んでいるのを見かけました。
https://www.amazon.co.jp/Bluetooth-Shutter-ABS3-BLK/dp/B00JX70WK4/
4 Raspberry PI
使用したのは、RaspberryPi 3Bで、OSは、今年4月の最新版(Raspberry Pi OS with desktop)です。
3Bでは、最初からBluetoothが利用可能なので、特にドングルを用意する必要なありません。
$ cat /proc/cpuinfo | grep Revision Revision : a32082 $ lsb_release -a No LSB modules are available. Distributor ID: Raspbian Description: Raspbian GNU/Linux 10 (buster) Release: 10 Codename: buster $ uname -a Linux raspberrypi 5.10.17-v7+ #1414 SMP Fri Apr 30 13:18:35 BST 2021 armv7l GNU/Linux
5 ペアリング
Bluetoothのペアリングは、RaspberryPiで利用可能な、bluetoothctlを使用しました。
(1) 起動
$ bluetoothctl Agent registered [bluetooth]#
(2) スキャン
scan onで、電源ONとなっている周辺のBluetoothデバイスが列挙できるので、対象(AB Shutter3)のアドレスを控えます。
[bluetooth]# scan on Discovery started [NEW] Device 2A:1B:3C:11:22:38 AB Shutter3 ・・・略・・・ [bluetooth]# devices Device 2A:1B:3C:11:22:38 AB Shutter3 ・・・略・・・ [bluetooth]# scan off Discovery stopped
(3) ペアリング
pair/removeでペアリング及び、解除ができます。 下記では、デバイスをペアリングして、ペアリング中のデバイス一覧しています。
[AB Shutter3]#pair 2A:1B:3C:11:22:38 Attempting to pair with 2A:1B:3C:11:22:38 [AB Shutter3]# paired-devices Device 2A:1B:3C:11:22:38 AB Shutter3
(4) 信頼
trustで、デバイスを信頼しておくことで、再起動後もペアリング有効になります。
[AB Shutter3]# trust 2A:1B:3C:11:22:38 [CHG] Device 2A:1B:3C:11:22:38 Trusted: yes Changing 2A:1B:3C:11:22:38 trust succeeded
[AB Shutter3]# exit $
(5) /dev/input/evdev0
認識されているリモコンは、入力デバイスとして/dev/input/の配下に見つけることができます。
$ ls -la /dev/input total 0 drwxr-xr-x 2 root root 100 Sep 26 14:59 . drwxr-xr-x 16 root root 3660 Sep 26 14:59 .. crw-rw---- 1 root input 13, 64 Sep 26 14:59 event0 crw-rw---- 1 root input 13, 63 Sep 26 14:59 mice
6 権限追加
Greengrassで、デフォルトのユーザー(ggc_user)を使用する場合、GPIO及び、入力デバイスでパーミッションエラーが発生してしまいます。
stderr. GPIO.setup(PATLAMP, GPIO.OUT).
stdout. Exception [Errno 13] Permission denied: '/dev/input/event0'.
どちらも、グループに追加することで、解消可能です。
$ sudo usermod -G input,gpio ggc_user $ cat /etc/group | grep ggc_user input:x:105:pi,ggc_user gpio:x:997:pi,ggc_user ggc_user:x:995:
7 アーティクル
下記が、本体コードとなります。
それぞれ役割ごとにクラスになっています。
- Patramp パトライト制御クラス(GPIO処理)
- Bluetooth Bluetooth受信クラス
- Mqtt MQTT送受信クラス
Greenglassのセットアップや、コンポーネントの作成、MQTTのPub/Subについては、下記の記事をご参照ください。
[AWS IoT Greengrass V2] RaspberryPIにインストールしてみました
[AWS IoT Greengrass V2] RaspberryPIでコンポーネントを作成してみました
[AWS IoT Greengrass V2] コンポーネントからIoT CoreのメッセージブローカーにPublish/Subscribeしてみました
import time import glob import RPi.GPIO as GPIO import evdev import json import awsiot.greengrasscoreipc import awsiot.greengrasscoreipc.client as client from awsiot.greengrasscoreipc.model import ( IoTCoreMessage, QOS, PublishToIoTCoreRequest, SubscribeToIoTCoreRequest ) # パトライト制御クラス class Patramp(): def __init__(self, gpio) -> None: self.PATLAMP = gpio GPIO.setmode(GPIO.BCM) GPIO.setup(self.PATLAMP, GPIO.OUT) def on(self): GPIO.output(self.PATLAMP, 1) def off(self): GPIO.output(self.PATLAMP, 0) # Bluetooth受信クラス class Bluetooth(): def __init__(self) -> None: inputs = glob.glob('/dev/input/event*') if(len(inputs) <= 0): print('device not found.') exit(0) self.input = inputs[0] print(self.input) def recv(self): self.device = evdev.InputDevice(self.input) for event in self.device.read_loop(): if(event.type == 1): if(event.code == 28): return 1 elif(event.code == 115): return 0 return -1 # MQTT送受信クラス class Mqtt(): def __init__(self) -> None: self.ipc_client = awsiot.greengrasscoreipc.connect() self.timeout = 10 class StreamHandler(client.SubscribeToIoTCoreStreamHandler): def __init__(self, on_recv): super().__init__() self.__on_recv = on_recv def on_stream_event(self, event: IoTCoreMessage) -> None: message = str(event.message.payload, "utf-8") print("onRecv payload:{}".format(message)) self.__on_recv(json.loads(message)) def on_stream_error(self, error: Exception) -> bool: return True def on_stream_closed(self) -> None: pass def subscribe(self, topic, on_recv): qos = QOS.AT_LEAST_ONCE request = SubscribeToIoTCoreRequest() request.topic_name = topic request.qos = qos handler = self.StreamHandler(on_recv) operation = self.ipc_client.new_subscribe_to_iot_core(handler) future = operation.activate(request) future.result(self.timeout) def publish(self, topic, payload): qos = QOS.AT_LEAST_ONCE request = PublishToIoTCoreRequest() request.topic_name = topic request.payload = json.dumps(payload).encode('utf-8') request.qos = qos operation = self.ipc_client.new_publish_to_iot_core() operation.activate(request) future = operation.get_response() future.result(self.timeout) print("publish :{}".format(payload)) time.sleep(1) gpio = 17 # GPIO 17 patraml = Patramp(gpio) bluetooth = Bluetooth() def on_recv(message): if(message["sw"] == "ON"): patraml.on() else: patraml.off() topic = "patramp/100" mqtt = Mqtt() mqtt.subscribe(topic, on_recv) while True: try: result = bluetooth.recv() if(result != -1): if(result == 0): sw = "ON" else: sw = "OFF" mqtt.publish(topic, { "sw": sw }) except Exception as e: print('Exception {}'.format(e)) time.sleep(1)
8 レシピ
レシピです。 デフォルトCoonfigrationのaccessControlでIoTCoreに対するPublishとSubscribeが許可されています。
--- RecipeFormatVersion: 2020-01-25 ComponentName: com.example.Patramp ComponentVersion: '1.0.4' ComponentConfiguration: DefaultConfiguration: accessControl: aws.greengrass.ipc.mqttproxy: com.example.Patramp:mqtt:1: operations: - "aws.greengrass#PublishToIoTCore" - "aws.greengrass#SubscribeToIoTCore" resources: - "patramp/#" Manifests: - Platform: os: linux Lifecycle: Install: pip3 install evdev awsiotsdk Run: python3 -u {artifacts:path}/patramp.py Artifacts: - URI: s3://gg-artifacts-2021-08-11/artifacts/com.example.Patramp/1.0.0/patramp.py
9 最後に
今回は、Bluetoothのリモコンでパトランプを操作するコンポーネントを作成してみました。慣れてくると、普通のツールを作成するのと、コンポーネントを作成するのに、それほど差異を感じなくなってきます。
要件が許す場合、ありがたくGreengrassの恩恵を受けれるように、色々試しておきたいと思っています。
10 参考リンク
[AWS IoT Greengrass V2] RaspberryPIにインストールしてみました
[AWS IoT Greengrass V2] RaspberryPIでコンポーネントを作成してみました
[AWS IoT Greengrass V2] クラウド側から複数のコアデバイスにコンポーネントをデプロイしてみました
[AWS IoT Greengrass V2] クラウド側からコンポーネントを削除してみました
[AWS IoT Greengrass V2] ローカルデバッグコンソール(aws.greengrass.LocalDebugConsole)を使用してみました
[AWS IoT Greengrass V2] Lambda関数(コンポーネント)をデプロイしてみました
[AWS IoT Greengrass V2] コンポーネントからIoT CoreのメッセージブローカーにPublish/Subscribeしてみました
[AWS IoT Greengrass V2] コンポーネントからシークレットマネージャにアクセスしてみました
[AWS IoT Greengrass V2] コンポーネントでコアデバイス間のPublish/Subscribeを試してみました
[AWS IoT Greengrass V2] ログマネージャでコンポーネントのログをCloudWatch Logsに送ってみました
[AWS IoT Greengrass V2] トークン交換サービスでコンポーネントからDynamoDBにアクセスしてみました
[AWS IoT Greengrass V2] ストリームマネージャーを使用してコンポーネントからKinesis Data Streamsへデータを送ってみました
[AWS IoT Greengrass V2] プロセス間通信 (IPC) を使用してコンポーネントの設定値を使用してみました
[AWS IoT Greengrass V2] ストリームマネージャーを使用してWebカメラの画像を毎秒2フレームでS3に送信してみました